package com.hbnu.service;

import com.hbnu.dao.FileTransferDao;
import com.hbnu.dao.UserDao;
import com.hbnu.entity.FileStat;
import com.hbnu.entity.UserFile;
import com.hbnu.enums.Status;
import com.hbnu.server.ftf.FileServer;
import com.hbnu.server.http.HttpServer;
import com.hbnu.tools.FileTool;

import java.io.File;
import java.io.IOException;
import java.util.*;

import static com.hbnu.service.FunctionService.fileService;
import static com.hbnu.service.FunctionService.userFileService;
import static com.hbnu.tools.FileTool.*;
import static com.hbnu.tools.PrintTool.print;
import static com.hbnu.tools.PrintTool.println;
import static com.hbnu.tools.ScannerTool.nextLine;
import static com.hbnu.tools.UserFileTool.*;
import static com.hbnu.web.Client.*;
import static com.hbnu.web.Client.idUserFileMap;

public class FileTransferService extends AbstractFunctionService {
    private final FileTransferDao fileTransferDao=new FileTransferDao();
    private final UserDao userDao=new UserDao();


    public FileTransferService() {
        oneMap.put("ftf",this::ftf);
        oneMap.put("down",this::down);
        oneMap.put("downid",this::downid);
        oneMap.put("downall",this::downall);
        oneMap.put("up",this::up);

        twoMap.put("down",this::down);
        twoMap.put("downid",this::downid);
        twoMap.put("up",this::up);
        twoMap.put("upid",this::upid);

    }

    //down 123.txt/文件夹（默认文件夹假设已经有了）
    private void down(String p) {
        down0(Status.def_ClientPath,pathToFid(p),idUserFileMap);
    }
    //down E:/123/d 123.txt
    private void down(String filePath,String p) {
        File file=new File(filePath);
        if(existsAndIsFolder(file)) down0(file.getAbsolutePath(),pathToFid(p),idUserFileMap);
    }
    private void downid(String id) {
        down0(Status.def_ClientPath,idToFid(id),idUserFileMap);
    }
    //down E:/123/d 123.txt
    private void downid(String filePath,String id) {
        File file=new File(filePath);
        if(existsAndIsFolder(file)) down0(file.getAbsolutePath(),idToFid(id),idUserFileMap);
    }
    //id,id,id,id
    private void downall(String ids){
        String[] split = ids.split(",");
        for (String s : split) {
            downid(s);
        }
    }
    //p为有效地址 传入对应文件map
    public void down0(String path, int fid, Map<Integer, UserFile> idUserFileMap) {
        if(fid==-1) return;
        UserFile userFile = idUserFileMap.get(fid);
        if(existsFileName(path,userFile.getFname())) return;
        path=path+"/"+userFile.getFname();
        //下载是文件
        if(userFile.is_file())
            downFile(userFile,path);
        else downFolder(userFile,path,idUserFileMap);  //下载的是文件夹
    }
    //获取一个文件夹fid
    private void downFile(UserFile userFile, String path) {
        int fid=userFile.getFid();
        //获取文件信息
        FileStat fileStat = userFileService.getFileStat(fid);
        try {
            //空文件自己造
            if(fileStat.getSize()==0) {
                if (!new File(path).createNewFile()) {
                    println("创建空文件失败！");
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //发起请求下载
        if(!fileService.download(fileStat,path)){
            println("下载服务异常！");
        }
    }
    private void downFolder(UserFile userFile, String localPath,Map<Integer, UserFile> idUserFileMap) {
        //创建一个文件夹
        if(!new File(localPath).mkdir()) {
            print("创建文件夹异常！");
            return;
        }
        if(!userFile.hasChildren()) return;
        Queue<Integer> fidQueue = new LinkedList<>(userFile.getList());
        //fid和本地地址的Map
        Map<Integer,String> fidLocalPathMap=new HashMap<>();
        fidLocalPathMap.put(userFile.getFid(),localPath);
        while (!fidQueue.isEmpty()) {
            int fid = fidQueue.poll();
            userFile = idUserFileMap.get(fid);
            localPath = fidLocalPathMap.get(userFile.getPid())+"/"+userFile.getFname();
            if (userFile.is_file()) {
                downFile(userFile,localPath);continue;
            }
            //文件夹  创建
            if(!new File(localPath).mkdir()) {
                print(localPath);
                println("创建文件夹异常！");
                return;
            }
            if(!userFile.hasChildren()) continue;
            fidQueue.addAll(userFile.getList());
            fidLocalPathMap.put(fid,localPath);//留给儿子用
        }
    }



    //up 文件地址
    private void up(String filePath) {
        up0(folder.getFid(),filePath);
    }
    //up /root/123 文件地址
    private void up(String path,String filePath) {
        //先获得pid
        up0(pathToFid(path),filePath);
    }
    //up id 文件地址
    private void upid(String id,String filePath) {
        //先获得pid
        up0(idToFid(id),filePath);
    }
    private void up0(int fid,String filePath) {
        //先获得pid
        File file = new File(filePath);
        //文件或文件夹
        if(!file.exists()){
            println("文件不存在！");
            return;
        }
        if(existFName(fid,file.getName())){
            println("文件重名！");
            return;
        }
        //判断内存是否可以存储
        if(user.getSpace()-user.getSize()<calculateFolderSize(file)){
            println("空间不足,无法保存!");
            return;
        }
        if(file.isFile()) {
            upFile(file,fid);
        }
        else{
            upFolder(file,fid);
        }
    }
    //判断文件是否存在、文件夹有没有同名
    private void upFile(File file,int pid) {
        //第一次上传
        boolean isFirst=false;
        print("获取文件MD5中....\r");
        String md5 = FileTool.calculateMD5(file);
        println(file.getName()+"\tmd5: "+md5);
        int file_id=fileTransferDao.checkMd5(md5);
        String path=idUserFileMap.get(pid).getPath()+"/"+file.getName();
        //不存在
        if(file_id==-1){
            //直接上传
            isFirst=true;
            String sPath = Status.ServerPath +"/"+ md5 + "." + getFileExtension(file);//文件后缀
            if(fileService.upload(file, sPath)){
                file_id = fileTransferDao.insertFileData(user.getUid(), file.length(), md5, sPath);
            }else {
                println("文件服务器上传异常！");return;
            }
        }
        //存在,则添加用户记录
        int fid=fileTransferDao.saveUserFile( user.getUid(), file.getName(), pid, file_id);
        //修改存储空间
        if(file.length()!=0){
            userDao.updateAddSize(user.getUid(),file.length());
            user.setSize(user.getSize()+file.length());
        }
        //存到用户缓存
        pathIdMap.put(path,fid);
        idUserFileMap.get(pid).addList(fid);
        idUserFileMap.put(fid,new UserFile(fid,pid,file.getName(),file_id,true,path));
        //秒传,即md5重复
        if(!isFirst) println(file.getName()+"\t上传完成!\t100.00%\t耗时0.0s");
    }
    //上传文件夹 : 文件不生成服务器，只是记录在数据库
    private void upFolder(File rootFile,int pid) {
        //创建文件夹
        pid=userFileService.mkdir(idUserFileMap.get(pid).getPath()+"/"+rootFile.getName(),rootFile.getName(),pid);
        //还有子文件
        File[] list = rootFile.listFiles();
        if(list==null||list.length==0) return;
        Queue<File> fileQueue=new LinkedList<>();
        Collections.addAll(fileQueue,list);
        Map<File,Integer> fileMap=new HashMap<>();
        fileMap.put(rootFile,pid);
        while (!fileQueue.isEmpty()){
            File file = fileQueue.poll();
            pid = fileMap.get(file.getParentFile());
            if(file.isFile()) {
                upFile(file,pid);continue;
            }
            pid=userFileService.mkdir(idUserFileMap.get(pid).getPath()+"/"+file.getName(),file.getName(),pid);
            //还有子文件
            File[] listFiles = file.listFiles();
            if(listFiles==null||listFiles.length==0) continue;
            fileMap.put(file,pid);
            Collections.addAll(fileQueue,listFiles);
        }
    }

    //面对面传输功能
    //发送：通常简写为 Tx 或 TX。这个缩写来源于英文单词 "Transmit"。
    //接收：通常简写为 Rx 或 RX。这个缩写来源于英文单词 "Receive"
    private void ftf(String cmd){
        if("tx".equals(cmd)){
            tx();
            //恢复ip
            fileService.setIp(Status.host);
        }else if("rx".equals(cmd)){
            rx();
        }else if("http".equals(cmd)){
            http();
        }else {
            println("命令错误！");
        }
    }
    private void tx(){
        String ip;
        do {
            print("对方IP: ");
            ip = nextLine();
            if (ip.isEmpty()) return;
        } while (!isValidIPAddress(ip));
        //改变文件发送的IP
        fileService.setIp(ip);
        println("测试连接中...");
        //获取对方上传地址
        fileService.initPath();
        String path;
        //进行文件传输
        while (true) {
            print("上传本地文件: ");
            path = nextLine();
            if (path.isEmpty()) return;
            //进行文件判断
            File file=new File(path);
            if(!file.exists()) {
                println("路径异常！");continue;
            }
            if(file.isDirectory()) {
                println("不支持文件传输,请压缩后发送!");continue;
            }
            //
            if(!fileService.upload(file, Status.SendPath+"/"+file.getName())) {
                println("上传异常");return;
            }
        }
    }
    //E:/视频/result/FileSystem/pom.xml
    private void rx(){
        println("本机IP: "+FileTool.getIP());
        new FileServer();
    }
    //http上传
    private void http(){
        new HttpServer();
    }

}
